﻿package bdz.controls {
	import bdz.common.events.NetStreamManagerEvent;
	import bdz.common.managers.NetStreamManager;
	import bdz.extensions.youtube.events.YTPlayerEvent;
	import bdz.extensions.youtube.ui.YTChromelessPlayer;
	
	import flash.display.*;
	import flash.events.*;
	import flash.geom.Point;
	import flash.media.Video;
	import flash.utils.*;
	import flash.geom.*;
	/**
	 * ...
	 * @author Donald
	 */
	public class VideoPlayback extends MovieClip {
		
		[Event (name = "complete", type = "flash.events.Event")]
		
		private var _vidControl:VideoController;
		private var _videoLayer:Video;
		private var _nsmanager:NetStreamManager;
		private var _vwidth:Number;
		private var _vheight:Number;
		private var _offset:Number = 5;
		private var _created:Boolean = false;
		private var _hasfullscreen:Boolean = true;
		private var _hasvolumecontrol:Boolean = true;
		private var _autoAlignControl:Boolean = true;
		private var _autoHideVolume:Boolean = true;
		private var _youtube:Boolean = false;
		private var _chromeless:YTChromelessPlayer;
		private var _tubeId:String;
		private var _hideYoutubeWatermark:Boolean = false;
		private var _displayParent:DisplayObject;
		private var _loc:Point;
		private var _stageState:String;
		private var _autoHideControls:Boolean = false;
		private var _buffer:Number = .3;
		private var _bufferPlay:Boolean = false;
		private var _autoPlay:Boolean = true;
		private var _bufferRenderer:String;
		private var _bufferClip:MovieClip;
		private var _bounds:MovieClip;
		private var _alignOffset:Number = 0;
		private var _defSkin:String = "VideoControl";
		private var _skinClass:Object;
		private var _autoSize:Boolean = false;
		private var _defControlHeight:Number;
		private var _onstage:Boolean = false;
		private var _sourced:Boolean = false;
		private var _cachedsource:String;
		
		private var myparent:*;
		private var parentspecs:Object;
		private var _videoContainer:MovieClip;
		public var useRect:Boolean = false;
		function VideoPlayback(w:Number = 640, h:Number = 480) {
			_vwidth = w;
			_vheight = h;
			addEventListener(Event.ADDED_TO_STAGE, listenToStage);
		}
		
		private function listenToStage(evt:Event):void {
			myparent = parent;
			_bounds = new MovieClip();
			_bounds.graphics.beginFill(0, 0);
			_bounds.graphics.drawRect(0, 0, _vwidth, _vheight);
			_bounds.graphics.endFill();
			addChild(_bounds);
			stage.addEventListener(FullScreenEvent.FULL_SCREEN, onStageChange);
			stage.addEventListener(Event.RESIZE, onStageResize);
			_onstage = true;
			if(_sourced){
				source = _cachedsource;
			}
		}
		
		private function createStream():void {
			
			_nsmanager = new NetStreamManager();
			_nsmanager.volume = 1;
			_nsmanager.vsource = _videoLayer;
			if(_bufferPlay){
				_nsmanager.autoPlay = false;
			}else {
				_nsmanager.autoPlay = _autoPlay;
			}
			_nsmanager.refreshRate = 100;
			_nsmanager.loadOffset = 0;
			_vidControl.stream = _nsmanager;
			_nsmanager.addEventListener(NetStreamManagerEvent.META_DATA, onStreamMeta);
			_nsmanager.addEventListener (NetStreamManagerEvent.PLAY_COMPLETE, onPlayComplete);
			_nsmanager.addEventListener(NetStreamManagerEvent.LOAD_PROGRESS, onStreamLoadProgress);
			_nsmanager.addEventListener(NetStreamManagerEvent.BUFFERING, checkBufferClip);
			_nsmanager.addEventListener (NetStreamManagerEvent.BUFFER_FULL, checkBufferClip);
			_nsmanager.addEventListener (NetStreamManagerEvent.PLAY_PROGRESS, onPlayProgress);
			
		}
		private function onPlayProgress(evt:NetStreamManagerEvent):void {
			
			dispatchEvent(evt);
		}
		private function onStreamMeta(evt:NetStreamManagerEvent):void{
			if(_autoSize){
				handleSizing(evt.data.width, evt.data.height);
			}
			dispatchEvent(evt);
		}
		private function onStreamLoadProgress(evt:NetStreamManagerEvent):void {
			
			if (evt.data.percent >= _buffer && _bufferPlay) {
				_nsmanager.play();
			}
		}
		private function initializeComponent(evt:Event = null):void {
			
			_sourced = true;
			
			if(!_onstage) return;
			var vc:Object = getDefinitionByName(_defSkin);
			if (_skinClass) {
				_vidControl = new _skinClass();
			}else {
				_vidControl = new vc();
			}
			
			_vidControl.hasFullscreen = _hasfullscreen;
			_vidControl.autoHideVolume = _autoHideVolume;
			_vidControl.autoHideControls = _autoHideControls;
			
			_videoContainer = new MovieClip();
			addChild(_videoContainer);
			if (!_youtube) {
				_videoLayer = new Video(_vwidth, _vheight);
				_videoLayer.smoothing = true;
				_videoContainer.addChild(_videoLayer);
				createStream();
			}else {
				_chromeless = new YTChromelessPlayer(_vwidth, _vheight);
				_chromeless.hideWatermark = _hideYoutubeWatermark;
				_chromeless.addEventListener(YTPlayerEvent.READY, onYouTubeReady);
				_vidControl.ytchromeless = true;
				_vidControl.ytstream = _chromeless;
				_videoContainer.addChild(_chromeless);
			}
			_vidControl.addEventListener("onFullScreen", handleFullscreenClick);
			_vidControl.enabled = false;
			if(_defControlHeight){
				_vidControl.defControlHeight = _defControlHeight;
			}
			addChild(_vidControl);
			
			if(_autoAlignControl){
				_vidControl.x = Math.ceil(_videoLayer.width/2)-Math.ceil(_vidControl.width/2);
				_vidControl.y = Math.ceil(_videoLayer.height - (_vidControl.height+_offset));
			}else {
				//default snaps to bottom of video
				_vidControl.x = Math.ceil(_videoLayer.width/2)-Math.ceil(_vidControl.width/2);
				_vidControl.y = Math.ceil(_vheight)+_alignOffset;
			}
			_created = true;
			
		}
		

		private function checkBufferClip(evt:NetStreamManagerEvent):void {
			if (evt.type == NetStreamManagerEvent.BUFFER_FULL) {
				try {
					removeChild(_bufferClip);
				}catch(e:Error){}
			}else {
				
				if(!_nsmanager.paused){
					createBufferClip();
				}
			}
		}
		private function createBufferClip():void {
			if(!_bufferRenderer) return;
			try {
				removeChild(_bufferClip);
			}catch(e:Error){}
			var bc:Object = getDefinitionByName(_bufferRenderer);
			_bufferClip = new bc() as MovieClip;
			_bufferClip.x = Math.ceil(_videoLayer.width / 2);
			_bufferClip.y = Math.ceil(_videoLayer.height / 2);
			addChild(_bufferClip);
			//setChildIndex(_bufferClip, numChildren - 1);
		}
	
		private function onPlayComplete(e:NetStreamManagerEvent):void {
			dispatchEvent ( new Event (Event.COMPLETE) );
		}
		private function onStageResize(evt:Event):void {
			if(stage){
				if(_vidControl == null) {
					stage.removeEventListener(Event.RESIZE, onStageResize);
					return;
				}
				if(stage.displayState == StageDisplayState.NORMAL){
					_vidControl.isFullScreen = false;
					
				}else {
					_vidControl.isFullScreen = true;
					
				}
			}
		}
		private function onStageChange(evt:FullScreenEvent):void {
			if(!_autoHideControls && _vidControl){
				_vidControl.isFullScreen = evt.fullScreen;
			}
			
		}
		private function loadMeToRoot():void {
			parent.removeChild(this);
			width = root.stage.stageWidth;
			height = root.stage.stageHeight;
			root.stage.addChild(this);
		}
		private function returnMeToMyParent():void {
			parent.removeChild(this);
			myparent.addChild(this);
			width = parentspecs.width;
			height = parentspecs.height;
			x = parentspecs.x;
			y = parentspecs.y;
		}
		private function handleFullscreenClick(evt:Event):void {
			if (stage.displayState != StageDisplayState.FULL_SCREEN) {
				_stageState  = StageDisplayState.FULL_SCREEN;
				parentspecs = { x:x, y:y, width:width, height:height };
				myparent = parent;
				//loadMeToRoot();
				/*
				if(parent != root){
					stage.fullScreenSourceRect = new Rectangle(parent.x, parent.y, width, height);
				}else {
					stage.fullScreenSourceRect = new Rectangle(x, y, width, height);
				}*/
				if(useRect){
					//stage.fullScreenSourceRect = new Rectangle(x, y, width, height);
				}
				stage.displayState = StageDisplayState.FULL_SCREEN;
				_vidControl.isFullScreen = true;
			}else {
				//returnMeToMyParent();
				_stageState  = StageDisplayState.NORMAL;
				stage.displayState = StageDisplayState.NORMAL;
				_vidControl.isFullScreen = false;
			}
		}
		private function handleSizing(w:Number, h:Number):void {
			_vwidth = w;
			_vheight = h;
			if(!_videoLayer) return;
			_videoLayer.width = w;
			_videoLayer.height = h;
			
			if(_autoAlignControl){
				_vidControl.x = Math.ceil(_videoLayer.width/2)-Math.ceil(_vidControl.width/2)
				_vidControl.y = Math.ceil(_videoLayer.height - (_vidControl.height+_offset));
			}else {
				//default snaps to bottom of video
				_vidControl.x = Math.ceil(_videoLayer.width/2)-Math.ceil(_vidControl.width/2)
				_vidControl.y = Math.ceil(_vheight)+_alignOffset;
			}
			
		}
		private function onYouTubeReady(evt:YTPlayerEvent):void {
			if (evt.alternativePlayer) {
				removeChild(_vidControl);
			}
			var cloned:YTPlayerEvent = evt.clone() as YTPlayerEvent;
			dispatchEvent(cloned);
		}
		public function seek(sec:Number):void {
			_vidControl.seekTo(sec);
		}
		public function playVideo():void {
			try{
				_vidControl.displayResume();
				_nsmanager.play();
			}catch(e:Error){}
		}
		public function clear():void{
			try{
				_nsmanager.clear();
			}catch(e:Error){}
		}
		public function set autoAlignControl(b:Boolean):void {
			_autoAlignControl = b;
		}
		public function get autoAlignControl():Boolean {
			return _autoAlignControl;
		}
		public function set hasVolumeControl(b:Boolean):void {
			_hasvolumecontrol = b;
		}
		public function set hasFullscreen(b:Boolean):void {
			_hasfullscreen = b;
		}
		public function get hasFullscreen():Boolean {
			return _hasfullscreen;
		}
		public function set autoHideVolume(b:Boolean):void {
			_autoHideVolume = b;
		}
		public function get autoHideVolume():Boolean {
			return _autoHideVolume;
		}
		public function set source(str:String):void {
		
			if (!_created && _onstage) {
				initializeComponent();
			}else{
				_sourced = true;
				_cachedsource = str;
				return;
			}
			if (_bufferRenderer && _autoPlay) {
				createBufferClip();
			}
			
				
				_nsmanager.source = str;
				_vidControl.stream = _nsmanager;
			
		}
		public function set tubeId(s:String):void {
			_tubeId = s;
			_chromeless.loadVideo(tubeId);
		}
		public function get tubeId():String {
			return _tubeId;
		}
		public function set youtube(b:Boolean):void {
			_youtube = b;
			if (!_created) {
				initializeComponent();
			}
		}
		public function get youtube():Boolean {
			return _youtube;
		}
		public function pause():void {
			_vidControl.displayPause();
			_nsmanager.pause();
		}
		public function set autoHideControls(b:Boolean):void {
			_autoHideControls = b;
		}
		public function get autoHideControls():Boolean {
			return _autoHideControls;
		}
		public function setSize(w:Number, h:Number):void {
			handleSizing(w, h);
		}
		public function set hideYouTubeWatermark(b:Boolean):void {
			_hideYoutubeWatermark = b;
		}
		public function get hideYouTubeWatermark():Boolean {
			return _hideYoutubeWatermark;
		}
		public function set bufferPlay(b:Boolean):void {
			_bufferPlay = b;
			
		}
		public function set bufferRenderer(str:String):void {
			_bufferRenderer = str;
		}
		public function set autoPlay(b:Boolean):void {
			_autoPlay = b;
		}
		public function get autoPlay():Boolean {
			return _autoPlay;
		}
		public function set buffer(n:Number):void {
			_buffer = n;
		}
		public function set alignOffset(n:Number):void {
			_alignOffset = n;
		}
		public function get alignOffset():Number {
			return _alignOffset;
		}
		public function set skinClass(o:Object):void {
			_skinClass = o;
		}
		public function get skinClass():Object{
			return _skinClass;
		}
		public function set autoSize(b:Boolean):void{
			_autoSize = b;
		}
		public function get autoSize():Boolean{
			return _autoSize;
		}
		public function set defControlHeight(n:Number):void{
			_defControlHeight = n;
		}
		public function get defControlHeight():Number{
			return _defControlHeight;
		}
		
		
		public function addOverVideo(mc:MovieClip):void {
			
			_videoContainer.addChild(mc);
		}
		public function removeOverVideo(mc:MovieClip):void {
			
			_videoContainer.removeChild(mc);
			
		}
		public function get stream():NetStreamManager{
			return _nsmanager;
		}
	}
	
}